package device

import chisel3._
import chisel3.util._
import utils._
import bus._
import common.Constants.XLEN
import yycore.LSUOpType

class ClintIO extends Bundle() {
  val mtip = Output(Bool())
  val msip = Output(Bool())
}

/*
* 当软件写1至msip寄存器触发软件中断，CSR寄存器mip中的MSIP置高指示当前中断等待（Pending）状态，
* 软件可通过写0至msip寄存器来清除该软件中断
*/
class AXI4CLINT(sim: Boolean = false) extends AXI4SlaveModule(new AXI4Lite, new ClintIO) {
  val msip = RegInit(0.U(64.W)) // 生成软件中断
  val mtime = RegInit(0.U(64.W))  // 计时器的值
  val mtimecmp = RegInit(0.U(64.W)) // 计时器的比较值

  val clk = (if(!sim) 10 else 1000)
  val freq = RegInit(clk.U(16.W))
  val inc = RegInit(1.U(16.W))

  val cnt = RegInit(0.U(16.W))
  val nextCnt = cnt + 1.U
  cnt := Mux(nextCnt < freq, nextCnt, 0.U)
  val tick = (nextCnt === freq)
  when(tick){
    mtime := mtime + inc
  }

  def getOffset(addr: UInt) = addr(15,0)
  val reg_raddr = raddr(15, 0)
  val reg_wadrr = waddr(15, 0)
  in.r.bits.data := MuxCase(0.U, Array(
    (reg_raddr === 0x0.U) -> msip,
    (reg_raddr === 0x4000.U) -> mtimecmp,
    (reg_raddr === 0x8000.U) -> freq,
    (reg_raddr === 0x8008.U) -> inc,
    (reg_raddr === 0xbff8.U) -> mtime
  ))
  when(in.w.fire()){
    when(reg_wadrr === 0x0.U){
      msip := MaskData(msip, in.w.bits.data, MaskExpand(in.w.bits.strb))
    }.elsewhen(reg_wadrr === 0x4000.U){
      mtimecmp := MaskData(mtimecmp, in.w.bits.data, MaskExpand(in.w.bits.strb))
    }.elsewhen(reg_wadrr === 0x8000.U){
      freq := MaskData(freq, in.w.bits.data, MaskExpand(in.w.bits.strb))
    }.elsewhen(reg_wadrr === 0x8008.U){
      inc := MaskData(inc, in.w.bits.data, MaskExpand(in.w.bits.strb))
    }.elsewhen(reg_wadrr === 0xbff8.U){
      mtime := MaskData(mtime, in.w.bits.data, MaskExpand(in.w.bits.strb))
    }.otherwise{
      printf("CLINT: addr ERROR!!!\n")
    }
  }

  io.extra.get.mtip := RegNext(mtime >= mtimecmp)
  io.extra.get.msip := RegNext(msip =/= 0.U)
}

class CLINT(sim: Boolean = false) extends Module {
  val io = IO(new Bundle() {
    val in = Flipped(new CoreLinkIO(XLEN))
    val out = new ClintIO
  })
  val msip = RegInit(0.U(64.W)) // 生成软件中断
  val mtime = RegInit(0.U(64.W))  // 计时器的值
  val mtimecmp = RegInit(0.U(64.W)) // 计时器的比较值

  val clk = (if(!sim) 10 else 1000)
  val freq = RegInit(clk.U(16.W))
  val inc = RegInit(1.U(16.W))

  val cnt = RegInit(0.U(16.W))
  val nextCnt = cnt + 1.U
  cnt := Mux(nextCnt < freq, nextCnt, 0.U)
  val tick = (nextCnt === freq)
  when(tick){
    mtime := mtime + inc
  }

  val (valid, addr) = (io.in.req.valid, io.in.req.bits.addr)
  val mask = LSUOpType.MakeMask(addr, io.in.req.bits.size)

  def getOffset(addr: UInt) = addr(15,0)
  val reg_addr = getOffset(addr)
  val ren = valid && io.in.isRead
  val wen = valid && io.in.isWrite
  io.in.resp.bits.rdata := MuxCase(0.U, Array(
    (reg_addr === 0x0.U) -> msip,
    (reg_addr === 0x4000.U) -> mtimecmp,
    (reg_addr === 0x8000.U) -> freq,
    (reg_addr === 0x8008.U) -> inc,
    (reg_addr === 0xbff8.U) -> mtime
  ))
  when(wen){
    when(reg_addr === 0x0.U){
      msip := MaskData(msip, io.in.req.bits.wdata, MaskExpand(mask))
    }.elsewhen(reg_addr === 0x4000.U){
      mtimecmp := MaskData(mtimecmp, io.in.req.bits.wdata, MaskExpand(mask))
    }.elsewhen(reg_addr === 0x8000.U){
      freq := MaskData(freq, io.in.req.bits.wdata, MaskExpand(mask))
    }.elsewhen(reg_addr === 0x8008.U){
      inc := MaskData(inc, io.in.req.bits.wdata, MaskExpand(mask))
    }.elsewhen(reg_addr === 0xbff8.U){
      mtime := MaskData(mtime, io.in.req.bits.wdata, MaskExpand(mask))
    }
  }
  io.in.resp.valid := valid
  io.in.req.ready := true.B
  io.in.resp.bits.cmd := Mux(wen, LinkBusCmd.writeResp, LinkBusCmd.readLast)

  io.out.mtip := RegNext(mtime >= mtimecmp)
  io.out.msip := RegNext(msip =/= 0.U)
}